iT邦幫忙

2023 iThome 鐵人賽

DAY 25
0
Modern Web

職缺資訊平台—Jobscanner系列 第 25

[開發] 資料彙整 - 乾淨的源頭

  • 分享至 

  • xImage
  •  

同一種資料在不同平台有各自呈現方式,除了抓取資料外,也要整理成方便使用的資料格式,保有乾淨的資料源頭,後續不管是在搜尋、排序上都會更快更方便,以下以整理薪資資料為例。

薪資

觀察三大求職平台,會出現的薪資格式大致如下

104:
月薪34,000~52,000元
月薪50,000元以上
年薪800,000~1,000,000元

yourator:
NT$ 50,000 - 65,000 (月薪)
NT$ 900,000 - 1,600,000 (年薪)
面議(經常性薪資達4萬元)
NT$ 700,000 - (年薪)

CakeResume:
4萬 ~ 10萬 TWD / 月
56萬 ~ 90萬 TWD / 年
4.8萬+ TWD / 月


初步觀察

  • 有區間、有單一數值 (4萬 ~ 10萬 或是 4萬+)
  • 數值表示方式 (4萬、40,000)
  • 有年薪、月薪、時薪、面議

薪資的給法主要有年薪或是月薪,沒有固定公式可以換算,將年薪/12 或是月薪x12 不一定正確,沒辦法將兩者混在一起排序。

其中僅 104 有「待遇高低」的排序方式,作法是將年薪、月薪職缺先各自排序,先顯示年薪排序再顯示月薪排序結果。若薪資非固定數值,使用最小值做排序依據。

https://ithelp.ithome.com.tw/upload/images/20231009/20128122LJK5CaEp9K.png
*截圖取自 104.com.tw。年薪 420,000 會排在月薪 130,000 之前

若要使用薪資做排序,可將薪資整理為一個陣列 [最小值, 最大值],只留下數值,最後 render 在畫面時,再決定 NT$千分號 等字串格式顯示。


範例

  1. 先區分為年薪、月薪、其他三類,例如:面議歸類為其他
  2. -~ 切分,將 salary 轉成陣列,例如 56萬 ~ 90萬 TWD / 年 會變成 ['56萬', '90萬 TWD / 年']
  3. 若有萬字,需將數值取出做運算,例如:56萬 會變成 560000 或是 4.8萬 會變成 48000
  4. 若沒有萬字,僅擷取出數值的部分,例如:NT$ 900,000 會變成 900000

原始數據

[
  {
    "id": 1,
    "name": "遊戲前端工程師助理",
    "salary": "月薪34,000~52,000元"
  },
  {
    "id": 2,
    "name": "前端網頁工程師(接案)",
    "salary": "年薪800,000~1,000,000元"
  },
  {
    "id": 3,
    "name": "Vue.js前端工程師",
    "salary": "NT$ 50,000 - 65,000 (月薪)"
  },
  {
    "id": 4,
    "name": "網頁前端工程師",
    "salary": "NT$ 900,000 - 1,600,000 (年薪)"
  },
  {
    "id": 5,
    "name": "遊戲前端工程師助理",
    "salary": "56萬 ~ 90萬 TWD / 年"
  },
  {
    "id": 6,
    "name": "網站前端工程師(台南)",
    "salary": "4萬 ~ 10萬 TWD / 月"
  },
  {
    "id": 7,
    "name": "網站前端工程師(台南)",
    "salary": "面議(經常性薪資達4萬元)"
  },
  {
    "id": 8,
    "name": "網站前端工程師(台南)",
    "salary": "4.8萬+ TWD / 月"
  }
]

整理薪資

const jobList = require("./salary.json");

const keyword = {
  year: "年",
  month: "月",
  tenThousand: "萬",
  dollar: "元",
};

let data = jobList.map((job) => {
  let salary = [],
      salaryType = "";

  // salaryType 區分類別
  if (job.salary.includes(keyword.month)) {
    salaryType = "month";
  } else if (job.salary.includes(keyword.year)) {
    salaryType = "year";
  } else {
    salaryType = "other";
  }

  // 以 - 或 ~ 切分,將 salary 轉成陣列
  salary = job.salary.split(/-|~/);

  salary = salary.map((item) => {
    // match 萬字前面的數值
    const withWordRegex = new RegExp(`\\d+\.?\\d?(?=${keyword.tenThousand})`);
    // match 數值
    const withThousandSeparatorRegex = /(\d+,?)+/;
    let value;

    if (item.includes(keyword.tenThousand)) {
      value = item.match(withWordRegex)[0] * 10000;
    } else if (withThousandSeparatorRegex.test(item)) {
      value = Number(
        item.match(withThousandSeparatorRegex)[0].replaceAll(",", "")
      );
    } else {
      value = item;
    }
    return value;
  });

  return {
    ...job,
    salary,
    salaryType,
  };
});

處理後的資料

[
  {
    id: 1,
    name: '遊戲前端工程師助理',
    salary: [ 34000, 52000 ],
    salaryType: 'month'
  },
  {
    id: 2,
    name: '前端網頁工程師(接案)',
    salary: [ 800000, 1000000 ],
    salaryType: 'year'
  },
  {
    id: 3,
    name: 'Vue.js前端工程師',
    salary: [ 50000, 65000 ],
    salaryType: 'month'
  },
  {
    id: 4,
    name: '網頁前端工程師',
    salary: [ 900000, 1600000 ],
    salaryType: 'year'
  },
  {
    id: 5,
    name: '遊戲前端工程師助理',
    salary: [ 560000, 900000 ],
    salaryType: 'year'
  },
  {
    id: 6,
    name: '網站前端工程師(台南)',
    salary: [ 40000, 100000 ],
    salaryType: 'month'
  },
  {
    id: 7,
    name: '網站前端工程師(台南)',
    salary: [ 40000 ],
    salaryType: 'other'
  },
  {
    id: 8,
    name: '網站前端工程師(台南)',
    salary: [ 48000 ],
    salaryType: 'month'
  }
]

上一篇
[開發] 資料彙整 - 觀察
下一篇
[開發] 資料彙整 - 評估
系列文
職缺資訊平台—Jobscanner31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言